package io.github.javpower.gifweb.util;

import com.madgag.gif.fmsware.AnimatedGifEncoder;
import com.madgag.gif.fmsware.GifDecoder;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.*;
import java.util.List;
import java.util.*;

public class GifTemplateUtil {

    /**
     * 将指定图片嵌入到模板 GIF 中，生成新的 GIF 并返回 Base64 编码的字符串
     */
    public static String applyTemplateToGif(String base64Gif, String templateParams, MultipartFile overlayImageFile) throws IOException {
        // 读取 Base64 编码的 GIF
        byte[] gifBytes = Base64.getDecoder().decode(base64Gif); // 去掉前缀，如 "data:image/gif;base64,"
        try (ByteArrayInputStream bis = new ByteArrayInputStream(gifBytes)) {
            GifDecoder gifDecoder = new GifDecoder();
            gifDecoder.read(bis);

            // 读取覆盖图片
            BufferedImage overlayImage = ImageIO.read(overlayImageFile.getInputStream());

            // 读取模板数据
            Map<Integer, List<List<Point>>> templateData = loadTemplateData(templateParams);

            // 创建新的 GIF
            AnimatedGifEncoder gifEncoder = new AnimatedGifEncoder();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            gifEncoder.start(baos);
            gifEncoder.setRepeat(0); // 无限循环

            // 处理每一帧
            for (int i = 0; i < gifDecoder.getFrameCount(); i++) {
                BufferedImage frame = gifDecoder.getFrame(i);
                List<List<Point>> polygons = templateData.get(i);

                if (polygons != null) {
                    // 创建新的帧图像
                    BufferedImage newFrame = new BufferedImage(
                            frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_ARGB
                    );
                    Graphics2D g2d = newFrame.createGraphics();

                    // 启用抗锯齿
                    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                    // 绘制原始帧
                    g2d.drawImage(frame, 0, 0, null);

                    // 将指定图片嵌入到多边形区域
                    for (List<Point> polygon : polygons) {
                        // 计算多边形区域的边界
                        Rectangle bounds = getPolygonBounds(polygon);

                        // 缩放和裁剪指定图片以适应多边形区域
                        BufferedImage scaledImage = scaleAndCropImage(overlayImage, bounds.width, bounds.height);

                        // 设置裁剪区域为多边形
                        Polygon clipPolygon = new Polygon();
                        for (Point p : polygon) {
                            clipPolygon.addPoint(p.x, p.y);
                        }
                        g2d.setClip(clipPolygon);

                        // 颜色适应：调整图片的亮度和对比度
                        BufferedImage adjustedImage = adjustImageColor(scaledImage, frame, bounds);

                        // 计算居中偏移量
                        int offsetX = bounds.x + (bounds.width - adjustedImage.getWidth()) / 2;
                        int offsetY = bounds.y + (bounds.height - adjustedImage.getHeight()) / 2;

                        // 边缘融合：设置透明度渐变
                        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.9f));
                        g2d.drawImage(adjustedImage, offsetX, offsetY, null);

                        // 恢复默认裁剪区域
                        g2d.setClip(null);
                    }

                    g2d.dispose();

                    // 添加新帧到 GIF
                    gifEncoder.setDelay(gifDecoder.getDelay(i)); // 保持原帧延迟
                    gifEncoder.addFrame(newFrame);
                } else {
                    // 如果没有多边形数据，直接添加原始帧
                    gifEncoder.setDelay(gifDecoder.getDelay(i)); // 设置帧延迟
                    gifEncoder.addFrame(frame); // 添加原始帧
                }
            }

            // 完成 GIF 编码
            gifEncoder.finish();

            // 将生成的 GIF 转换为 Base64 编码的字符串
            byte[] gifOutputBytes = baos.toByteArray();
            String base64GifOutput = Base64.getEncoder().encodeToString(gifOutputBytes);
            return "data:image/gif;base64," + base64GifOutput;
        }
    }

    // 加载模板数据
    private static Map<Integer, List<List<Point>>> loadTemplateData(String templateParams) {
        Map<Integer, List<List<Point>>> templateData = new HashMap<>();
        try (BufferedReader reader = new BufferedReader(new StringReader(templateParams))) {
            int currentFrame = -1;
            List<Point> currentPolygon = null;
            String line;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.startsWith("Frame: ")) {
                    currentFrame = Integer.parseInt(line.substring(7).trim());
                    templateData.put(currentFrame, new ArrayList<>());
                } else if (line.equals("---")) {
                    if (currentPolygon != null) {
                        templateData.get(currentFrame).add(currentPolygon);
                        currentPolygon = null;
                    }
                } else {
                    if (currentPolygon == null) {
                        currentPolygon = new ArrayList<>();
                    }
                    String[] parts = line.split(",");
                    int x = Integer.parseInt(parts[0]);
                    int y = Integer.parseInt(parts[1]);
                    currentPolygon.add(new Point(x, y));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return templateData;
    }

    // 计算多边形的边界
    private static Rectangle getPolygonBounds(List<Point> polygon) {
        int minX = Integer.MAX_VALUE;
        int minY = Integer.MAX_VALUE;
        int maxX = Integer.MIN_VALUE;
        int maxY = Integer.MIN_VALUE;

        for (Point p : polygon) {
            minX = Math.min(minX, p.x);
            minY = Math.min(minY, p.y);
            maxX = Math.max(maxX, p.x);
            maxY = Math.max(maxY, p.y);
        }

        return new Rectangle(minX, minY, maxX - minX, maxY - minY);
    }

    // 缩放和裁剪图片以适应目标区域
    private static BufferedImage scaleAndCropImage(BufferedImage image, int targetWidth, int targetHeight) {
        // 计算缩放比例
        double scaleX = (double) targetWidth / image.getWidth();
        double scaleY = (double) targetHeight / image.getHeight();
        double scale = Math.max(scaleX, scaleY);

        // 缩放图片
        int scaledWidth = (int) (image.getWidth() * scale);
        int scaledHeight = (int) (image.getHeight() * scale);
        BufferedImage scaledImage = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = scaledImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.drawImage(image, 0, 0, scaledWidth, scaledHeight, null);
        g2d.dispose();

        // 裁剪图片
        int x = (scaledWidth - targetWidth) / 2;
        int y = (scaledHeight - targetHeight) / 2;
        return scaledImage.getSubimage(x, y, targetWidth, targetHeight);
    }

    // 调整图片颜色以适应背景
    private static BufferedImage adjustImageColor(BufferedImage image, BufferedImage background, Rectangle bounds) {
        // 获取背景区域的平均颜色
        Color backgroundColor = getWeightedAverageColor(background, bounds);

        // 获取图片的平均颜色
        Color imageColor = getWeightedAverageColor(image, new Rectangle(0, 0, image.getWidth(), image.getHeight()));

        // 计算颜色差异
        float[] bgColorComponents = backgroundColor.getRGBColorComponents(null);
        float[] imgColorComponents = imageColor.getRGBColorComponents(null);

        // 计算颜色调整参数
        float[] scaleFactors = new float[3];
        float[] offsets = new float[3];
        for (int i = 0; i < 3; i++) {
            scaleFactors[i] = bgColorComponents[i] / imgColorComponents[i];
            offsets[i] = bgColorComponents[i] - imgColorComponents[i] * scaleFactors[i];
        }

        // 应用颜色调整
        RescaleOp colorAdjustOp = new RescaleOp(scaleFactors, offsets, null);
        BufferedImage adjustedImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
        colorAdjustOp.filter(image, adjustedImage);

        return adjustedImage;
    }

    // 获取图像区域的加权平均颜色
    private static Color getWeightedAverageColor(BufferedImage image, Rectangle region) {
        long redSum = 0, greenSum = 0, blueSum = 0;
        long weightSum = 0;

        for (int y = region.y; y < region.y + region.height; y++) {
            for (int x = region.x; x < region.x + region.width; x++) {
                if (x < image.getWidth() && y < image.getHeight()) {
                    Color color = new Color(image.getRGB(x, y), true);
                    int weight = (color.getRed() + color.getGreen() + color.getBlue()) / 3; // 使用亮度作为权重
                    redSum += color.getRed() * weight;
                    greenSum += color.getGreen() * weight;
                    blueSum += color.getBlue() * weight;
                    weightSum += weight;
                }
            }
        }

        if (weightSum == 0) {
            return Color.WHITE; // 默认返回白色
        }

        int avgRed = (int) (redSum / weightSum);
        int avgGreen = (int) (greenSum / weightSum);
        int avgBlue = (int) (blueSum / weightSum);

        return new Color(avgRed, avgGreen, avgBlue);
    }
}